import React, { StrictMode, useState, useRef, useImperativeHandle, useContext } from 'react'
// 导入classnames 可以使用vue中灵活的classname
import classnames from 'classnames'
// 用于对class组件的props进行定义
import PropTypes from 'prop-types';

import '../styles/less/common.less'

const boxStyle = {
    margin: '10px',
    border: '1px solid #ccc',
    borderRadius: '10px',
    padding: '10px',
}
export class PropTypesTemple extends React.Component {
    constructor(props) {
        super(props)
        this.state = {
            a: 1111,
            b: 222,
            isPrimary: false,
            size: 'large'
        }
    }
    componentDidMount() {
        const className = classnames('foo', 'bar');
        const className1 = classnames('foo', { bar: true, far: false });
        const className2 = classnames('a', ['b', { c: true }, { d: false }]);
        // null 和 undefined 会被忽略
        const className3 = classnames(null, false, 'bar', undefined, 0, 1, { baz: null }, '');
        const className4 = classnames([
            'btn',
            {
                'btn-primary': this.state.isPrimary,
                'btn-large': this.state.size === 'large',
            },
            'custom-class',
        ]);
        console.log('classnames', className)
        console.log('classnames1', className1)
        console.log('classnames2', className2)
        console.log('classnames3', className3)
        console.log('classnames4', className4)
    }
    render() {
        return (
            <div style={boxStyle} >
                <p className={classnames('colorBlue', 'fontSize12')}>classnames返回多个class</p>
                <p className={classnames(['a', true && 'b', false && 'c'], 'fontSize12')}>使用classname中数组参数</p>
                <UseStateDemo></UseStateDemo>
            </div>
        )
    }
}

function Son(props) {
    return (
        <>
            <p>使用propTypes定义props</p>
            <p>使用classname灵活使用class</p>
        </>
    )
}

export default function UseStateDemo() {
    // 1、存储列表选项的值
    let [arrData, setArrData] = useState([{ type: 'A', value: '选项1' }, { type: 'B', value: '选项2' }])
    // 2、存储选颜色的值
    let [liColor, setLiColor] = useState('A')
    const fn = (type) => {
        setLiColor(type)
    }
    return (
        <>
            <ul className="flex lineFlefx">
                {
                    arrData.map((item, index) => {
                        return <li onClick={() => fn(item.type)}
                            // 不使用classnames实现
                            // className={`item ${liColor === item.type ? 'active' : ''}`}
                            // 使用classname实现
                            className={classnames('buttonItem', { active: liColor === item.type })}
                            key={item.value}
                        >
                            {item.value}
                        </li>
                    })

                }

            </ul >
        </>

    )
}

// +++++++++++++++++++++++++++++ 如何使用propTypes, 定义props类型及是否必须 +++++++++++++++++++++++++++++++++
function MyComponent({ name }) {
    return (
        <div>Hello, {name}</div>
    )
}

// 指定 props 的默认值：
MyComponent.defaultProps = {
    name: 'Stranger'
};
class Message {
    a = 1111;
    b = 2222;
}
MyComponent.propTypes = {
    // 你可以将属性声明为 JS 原生类型，默认情况下
    // 这些属性都是可选的。
    optionalArray: PropTypes.array,
    optionalBool: PropTypes.bool,
    optionalFunc: PropTypes.func,
    optionalNumber: PropTypes.number,
    optionalObject: PropTypes.object,
    optionalString: PropTypes.string,
    optionalSymbol: PropTypes.symbol,

    // 任何可被渲染的元素（包括数字、字符串、元素或数组）
    // (或 Fragment) 也包含这些类型。
    optionalNode: PropTypes.node,

    // 一个 React 元素。
    optionalElement: PropTypes.element,

    // 一个 React 元素类型（即，MyComponent）。
    optionalElementType: PropTypes.elementType,

    // 你也可以声明 prop 为类的实例，这里使用
    // JS 的 instanceof 操作符。
    optionalMessage: PropTypes.instanceOf(Message),

    // 你可以让你的 prop 只能是特定的值，指定它为
    // 枚举类型。
    optionalEnum: PropTypes.oneOf(['News', 'Photos']),

    // 一个对象可以是几种类型中的任意一个类型
    optionalUnion: PropTypes.oneOfType([
        PropTypes.string,
        PropTypes.number,
        PropTypes.instanceOf(Message)
    ]),

    // 可以指定一个数组由某一类型的元素组成
    optionalArrayOf: PropTypes.arrayOf(PropTypes.number),

    // 可以指定一个对象由某一类型的值组成
    optionalObjectOf: PropTypes.objectOf(PropTypes.number),

    // 可以指定一个对象由特定的类型值组成
    optionalObjectWithShape: PropTypes.shape({
        color: PropTypes.string,
        fontSize: PropTypes.number
    }),

    // An object with warnings on extra properties
    optionalObjectWithStrictShape: PropTypes.exact({
        name: PropTypes.string,
        quantity: PropTypes.number
    }),

    // 你可以在任何 PropTypes 属性后面加上 `isRequired` ，确保
    // 这个 prop 没有被提供时，会打印警告信息。
    requiredFunc: PropTypes.func.isRequired,

    // 任意类型的必需数据
    requiredAny: PropTypes.any.isRequired,

    // 你可以指定一个自定义验证器。它在验证失败时应返回一个 Error 对象。
    // 请不要使用 `console.warn` 或抛出异常，因为这在 `oneOfType` 中不会起作用。
    customProp: function (props, propName, componentName) {
        if (!/matchme/.test(props[propName])) {
            return new Error(
                'Invalid prop `' + propName + '` supplied to' +
                ' `' + componentName + '`. Validation failed.'
            );
        }
    },

    // 你也可以提供一个自定义的 `arrayOf` 或 `objectOf` 验证器。
    // 它应该在验证失败时返回一个 Error 对象。
    // 验证器将验证数组或对象中的每个值。验证器的前两个参数
    // 第一个是数组或对象本身
    // 第二个是他们当前的键。
    customArrayProp: PropTypes.arrayOf(function (propValue, key, componentName, location, propFullName) {
        if (!/matchme/.test(propValue[key])) {
            return new Error(
                'Invalid prop `' + propFullName + '` supplied to' +
                ' `' + componentName + '`. Validation failed.'
            );
        }
    })
};